import info.gridworld.grid.AbstractGrid;
import info.gridworld.grid.Location;

import java.util.ArrayList;
import java.util.LinkedList;

public class SparseBoundedGrid1b<E> extends AbstractGrid<E> {

    private LinkedList<LinkedList<OccupantInCol>> occlist;
    private int numCols;
    private int numRows;

    public SparseBoundedGrid1b(int c, int r){
        if (r <= 0) {
            throw new IllegalArgumentException("Error! Rows <= 0");
        }
        if (c <= 0) {
            throw new IllegalArgumentException("Error! Cols <= 0");
        }
        occlist = new LinkedList<LinkedList<OccupantInCol>>();
        numCols = c;
        numRows = r;
        for (int i=0;i<r;i++){
            LinkedList<OccupantInCol> tmp = new LinkedList<>();
            occlist.add(tmp);
        }
    }

    @Override
    public int getNumRows() {
        return numRows;
    }

    @Override
    public int getNumCols() {
        return numCols;
    }

    @Override
    public boolean isValid(Location loc) {
        int c = loc.getCol();
        int r = loc.getRow();
        return 0 <= c && c < numCols && 0 <= r && r < numRows;
    }

    @Override
    public E put(Location loc, E obj) {
        if (!isValid(loc))
            throw new IllegalArgumentException("Location " + loc
                    + " is not valid");
        if (obj == null)
            throw new NullPointerException("obj == null");

        // remove old
        E old = remove(loc);

        int r = loc.getRow();
        int c = loc.getCol();

        LinkedList<OccupantInCol> p = occlist.get(r);
        // insert head
        p.add(new OccupantInCol(obj,c));

        return  old;
    }

    @Override
    public E remove(Location loc) {
        if (!isValid(loc)) {
            throw new IllegalArgumentException("Error! Location: " + loc + " is InValid.");
        }

        E old = get(loc);
        if (old == null)    return null;

        int r = loc.getRow();
        int c = loc.getCol();

        LinkedList<OccupantInCol> p = occlist.get(r);

        if (p.size()!=0){
            for (int i=0;i<p.size();i++){
                if (p.get(i).getCol() == c){
                    p.remove(i);
                    break;
                }
            }
        }

        return old;
    }

    @Override
    public E get(Location loc) {
        if (!isValid(loc)) {
            throw new IllegalArgumentException("Error! Location: " + loc + " is InValid.");
        }
        int r = loc.getRow();
        int c = loc.getCol();

        LinkedList<OccupantInCol> p = occlist.get(r);

        if (p.size()!=0){
            for (int i=0;i<p.size();i++){
                if (p.get(i).getCol() == c){
                    return (E)p.get(i).getOccupant();
                }
            }
        }

        return null;
    }

    @Override
    public ArrayList<Location> getOccupiedLocations() {
        ArrayList<Location> res = new ArrayList<>();

        for (int r=0; r<getNumRows(); r++){
            LinkedList<OccupantInCol> p = occlist.get(r);
            if (p.size()>0){
                for (int j=0;j<p.size();j++){
                    res.add(new Location(r,p.get(j).getCol()));
                }
            }

        }
        return res;
    }
}
